﻿// Ŭnicode please
#include "SimpleRenderApp_ES2.h"
#include <vector>
#include <mio.h>
#include <matsu.h>
#include <matsuExt.h>
#include "SRGLMachine.h"
#include "SRScene.h"
#include "SRModelLoader.h"
#include "CubeShaders.h"

#include "SRPrimitiveModel.h"

#if _GLES2_

using std::auto_ptr;
using namespace sora;
using namespace sora::gl;
using std::vector;


static const char gVertexShader[] = 
	"attribute vec4 vPosition;\n"
	"attribute vec4 srcColor;\n"
	"varying vec4 dstColor;\n"
	"void main() {\n"
	"	dstColor = srcColor;\n"
	"  gl_Position = vPosition;\n"
	"}\n";

static const char gFragmentShader[] = 
	"precision mediump float;\n"
	"varying lowp vec4 dstColor;\n"
	"void main() {\n"
	"  gl_FragColor = dstColor;\n"
	"}\n";

SimpleRenderApp::SimpleRenderApp()
{
	init();
}
SimpleRenderApp::~SimpleRenderApp()
{
	deinit();
}
void SimpleRenderApp::init()
{
	printGLString("Version", GL_VERSION);
	printGLString("Vendor", GL_VENDOR);
	printGLString("Renderer", GL_RENDERER);
	printGLString("Extensions", GL_EXTENSIONS);


	//load shader source
	//Shader *vertShader = Shader::createVertShader(gVertexShader);
	//Shader *fragShader = Shader::createFragShader(gFragmentShader);
	Shader *vertShader = Shader::createVertShader(cubeMeshVertexShader);
	Shader *fragShader = Shader::createFragShader(cubeFragmentShader);

	program_ = auto_ptr<ShaderProgram>(new ShaderProgram(vertShader, fragShader));

	// Use shader program.
	program_->use();

	// Validate program before drawing. This is a good check, but only really necessary in a debug build.
	// DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
	if (!program_->validate())
	{
		mio::Console::console().print("Failed to validate program: %x", program_.get());
		exit(-1);
	}
#endif

	//model그릴떄는 cull이 있으면 더 어렵다(모델정보 자체에 앞면 뒷면 정보는 거의 없으니까)
	//glEnable(GL_CULL_FACE);
	/*
	matsu::vec4 color(0, 1, 0, 1);
	model_ = auto_ptr<sora::Model>(new sora::WireTeapot(1, color));
	std::vector<DrawCommand> cmdList = model_->getDrawCommand();
	for(std::size_t i = 0 ; i < cmdList.size() ; i++)
	{
		const DrawCommand &cmd = cmdList[i];
		indexBuffer_ = auto_ptr<sora::IndexBufferObject>(new IndexBufferObject(cmd, GL_STATIC_DRAW));
		vertexBuffer_ = auto_ptr<sora::VertexBufferObject>(new VertexBufferObject(cmd, GL_STATIC_DRAW));
		break;
	}
	*/
	//obj model불러보기
	model_ = ModelLoader::loader().load("model/pawn.obj");
	
	//std::string p = mio::path::appPath("model/cube.obj");
	//LOGE(p.c_str());
}

void SimpleRenderApp::deinit()
{
}

void SimpleRenderApp::render(long tick, int width, int height)
{
	glViewport(0, 0, width, height);
	checkGlError("glViewport");

	static float grey;
	//grey += 0.01f;
	//if (grey > 1.0f) {
	//	grey = 0.0f;
	//}
	glClearColor(grey, grey, grey, 1.0f);
	checkGlError("glClearColor");
	glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	checkGlError("glClear");

	/*
	const sora::Vertex2 arrayVertices[] = {
		{{-0.5f, -0.5f}, {1, 0, 0, 1}},
		{{0.5f, -0.5f}, {0, 1, 0, 1}},
		{{0, 1.0f}, {0, 0, 1, 1}},
	};
	
	GLsizei vertexCount = sizeof(arrayVertices) / sizeof(sora::Vertex2);
	//program_->applyVertex2AttribArray(arrayVertices, vertexCount, GL_TRIANGLES);
	
	//shader 코드(쉐이더에서 해당 필드의 이름)에 따라서 구조가 완전히 바뀔수 있다
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	GLuint positionSlot = program_->getAttribLocation("vPosition");
	GLuint colorSlot = program_->getAttribLocation("srcColor");

	glEnableVertexAttribArray(positionSlot);
	glEnableVertexAttribArray(colorSlot);

	GLsizei stride = sizeof(Vertex2);
	const GLvoid *pCoords = &arrayVertices[0].pos[0];
	const GLvoid *pColors = &arrayVertices[0].color[0];

	glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);
	glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);

	glDrawArrays(GL_TRIANGLES, 0, vertexCount);

	glDisableVertexAttribArray(positionSlot);
	glDisableVertexAttribArray(colorSlot);
	
	*/
	//TODO: modelViewProjectionMatrix에 uniform설정
	{
		sora::Camera cam;
		//cam.setOrtho(-32, 32, -48, 48, 0, 1000);
		float aspect = (float)width / (float)height ;
		cam.setPerspective(45.0f, aspect, 0.1f, 100.0f );
		//matsu::mat4 modelview = matsu::mat::translate<float>(0, 0, 0);
		
		GLint projectionUniform = program_->getUniformLocation("modelViewProjectionMatrix");
		glUniformMatrix4fv(projectionUniform, 1, 0, cam.pointer());
		sora::gl::checkGlError("glUniformMatrix4fv");

		static float xrot = 0;
		static float yrot = 0;
		static float zrot = 0;

		static float zdist = 0;

		matsu::mat4 xRotate = matsu::mat::xRotate(xrot);
		matsu::mat4 yRotate = matsu::mat::yRotate(yrot);
		matsu::mat4 zRotate = matsu::mat::zRotate(zrot);

		matsu::mat4 translate = matsu::mat::translatef(0, 0, -5);
		matsu::mat4 scale = matsu::mat::scalef(0.002);

		matsu::mat4 modelview = xRotate * yRotate * zRotate * scale * translate;

		GLint modelviewUniform = program_->getUniformLocation("modelViewMatrix");
		glUniformMatrix4fv(modelviewUniform, 1, 0, modelview.pointer());
		sora::gl::checkGlError("glUniformMatrix4fv");

		xrot+=0.3f;
		yrot+=0.2f;
		zrot+=0.4f;

		//zdist -= 0.1f;
	}
	
	matsu::vec4 color(0, 1, 0, 1);
	//sora::WireSphere m(1, 16, 16, color);
	//sora::SolidSphere m(1, 16, 16, color);
	//sora::WireTeapot m(2, color);
	//sora::SolidTeapot m(2, color);
	//sora::WireCylinder m(1, 1, 16, color);
	//sora::SolidCylinder m(1, 1, 16, color);

	/*
	//vbo써서 그리기
	std::vector<DrawCommand> cmdList = model_->getDrawCommand();
	for(std::size_t i = 0 ; i < cmdList.size() ; i++)
	{
		const DrawCommand &cmd = cmdList[i];

		GLuint vertexPosition = program_->getAttribLocation("vertexPosition");	
		glEnableVertexAttribArray(vertexPosition);

		GLuint colorPosition = program_->getAttribLocation("srcColor");
		glEnableVertexAttribArray(colorPosition);

		const VertexPointer &ptr = cmd.pointer();
		glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_->buffer());
		glVertexAttribPointer(vertexPosition, 3, GL_FLOAT, GL_FALSE, vertexBuffer_->stride(), ptr.vertexOffset());
		glVertexAttribPointer(colorPosition, 4, GL_FLOAT, GL_FALSE, vertexBuffer_->stride(), ptr.colorOffset());

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_->buffer());
		glDrawElements(indexBuffer_->drawMode(), indexBuffer_->count(), indexBuffer_->indexType(), 0);
	}
	*/
	
	//그냥 그리기
	//sora::SolidTeapot m(2, color);
	//std::vector<DrawCommand> cmdList = m.getDrawCommand();

	//std::auto_ptr<Model> m(ModelLoader::loader().load("model/cube.obj"));
	std::vector<DrawCommand> cmdList = model_->getDrawCommand();
	for(std::size_t i = 0 ; i < cmdList.size() ; i++)
	{
		const DrawCommand &cmd = cmdList[i];

		GLuint vertexPosition = program_->getAttribLocation("vertexPosition");	
		glEnableVertexAttribArray(vertexPosition);
		
		GLuint colorPosition = program_->getAttribLocation("srcColor");
		glEnableVertexAttribArray(colorPosition);
		
		const VertexPointer &ptr = cmd.pointer();
		glVertexAttribPointer(vertexPosition, 3, GL_FLOAT, GL_FALSE, ptr.stride(), ptr.vertex());
		glVertexAttribPointer(colorPosition, 4, GL_FLOAT, GL_FALSE, ptr.stride(), ptr.color());
		glDrawElements(cmd.mode(), cmd.count(), cmd.type(), cmd.indices());
	}
	
	/*
	{
	sora::WireCylinder m1(1.1f, 1.1f, 16, color);

	std::vector<DrawCommand> cmdList = m1.getDrawCommand();
	for(std::size_t i = 0 ; i < cmdList.size() ; i++)
	{
		const DrawCommand &cmd = cmdList[i];

		GLuint vertexPosition = program_->getAttribLocation("vertexPosition");	
		glEnableVertexAttribArray(vertexPosition);

		glVertexAttribPointer(vertexPosition, 3, GL_FLOAT, GL_FALSE, cmd.pointer().stride(), cmd.pointer().vertex());
		glDrawElements(cmd.mode(), cmd.count(), cmd.type(), cmd.indices());
	}
	}
	*/
	/*
	const float *vertices = teapotVertices;
	const float *texCoords = teapotTexCoords;
	const float *normals = teapotNormals;
	const unsigned short *indices = teapotIndices;

	GLuint vertexPosition = program_->getAttribLocation("vertexPosition");
	GLuint vertexNormal = program_->getAttribLocation("vertexNormal");

	glEnableVertexAttribArray(vertexPosition);
	sora::gl::checkGlError("glEnableVertexAttribArray");
	glEnableVertexAttribArray(vertexNormal);
	sora::gl::checkGlError("glEnableVertexAttribArray");


	glVertexAttribPointer(vertexPosition, 3, GL_FLOAT, GL_FALSE, 0, vertices);
	sora::gl::checkGlError("glVertexAttribPointer");
	glVertexAttribPointer(vertexNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
	sora::gl::checkGlError("glVertexAttribPointer");

	glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT, indices);
	sora::gl::checkGlError("glDrawElements");
	*/


	/*
	const float *vertices = teapotVertices;
	const float *texCoords = teapotTexCoords;
	const float *normals = teapotNormals;
	const unsigned short *indices = teapotIndices;

	GLuint vertexPosition = program_->getAttribLocation("vertexPosition");
	GLuint vertexNormal = program_->getAttribLocation("vertexNormal");

	glEnableVertexAttribArray(vertexPosition);
	sora::gl::checkGlError("glEnableVertexAttribArray");
	glEnableVertexAttribArray(vertexNormal);
	sora::gl::checkGlError("glEnableVertexAttribArray");


	glVertexAttribPointer(vertexPosition, 3, GL_FLOAT, GL_FALSE, 0, vertices);
	sora::gl::checkGlError("glVertexAttribPointer");
	glVertexAttribPointer(vertexNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
	sora::gl::checkGlError("glVertexAttribPointer");

	glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT, indices);
	sora::gl::checkGlError("glDrawElements");
	*/
	
}

#endif